package com.chj.capt01;

/**
 * 常量池的变化
 * Java语言并不要求常量一定只能在编译期产生，也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池，
 * 运行期间也可能将新的常量放入池中，这种特性被开发人员利用得比较多的便是String类的intern()方法
 */
public class ConstantPool {
    public static void main(String[] args) {
        String b = "享学";
        String a = b + "课堂";
        /** public native String intern();方法中看到，这个方法是一个 native 的方法，但注释写的非常明了。
         * 如果常量池中存在当前字符串,就会直接返回当前字符串. 如果常量池中没有此字符串, 会将此字符串放入常量池中后, 再返回
         */
        System.out.println(a.intern() == a);
    }

    /**
     {
         public static void main(java.lang.String[]);
         descriptor: ([Ljava/lang/String;)V
         flags: ACC_PUBLIC, ACC_STATIC
         Code:
         stack=3, locals=3, args_size=1
         0: ldc           #2     // 这个操作码用来将常量从运行时常量池压栈到操作数栈  String 享学
         2: astore_1             // pop出栈引用值，将其（引用）赋值给局部变量表中的变量:String b
         3: new           #3     // 创建对象，并将对象引用压入栈。 class java/lang/StringBuilder
         6: dup                  // 将操作数栈定的数据复制一份，并压入栈，此时栈中有两个引用值
         7: invokespecial #4     // pop出栈引用值,调用其构造函数，完成对象的初始化。 Method java/lang/StringBuilder."<init>":()V
         10: aload_1              // 从局部变量位置为1的"b=享学"装载引用类型值入栈。
         11: invokevirtual #5     // 运行时方法绑定调用方法 append()。    // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
         14: ldc           #6     // 将常量“String 课堂”压入栈
         16: invokevirtual #5     // 绑定调用方法 append()——“享学+课堂”。    // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
         19: invokevirtual #7     // 绑定调用方法 toString()==“享学课堂”。  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
         22: astore_2             // 将栈中的“享学课堂”pop出栈，赋值给“String a”。
         23: getstatic     #8     // 用来把一个静态变量从运行时常量池的静态变量列表中压栈到操作数栈（final static PrintStream out） // Field java/lang/System.out:Ljava/io/PrintStream;
         26: aload_2              // 从局部变量"a(享学课堂)"中装载引用类型值入栈。
         27: invokevirtual #9     // 运行时方法绑定调用native方法 intern()。     // Method java/lang/String.intern:()Ljava/lang/String;
         30: aload_2              // 从局部变量"a(享学课堂)"中装载引用类型值入栈。
         31: if_acmpne     38     // 若栈顶两引用类型值不相等则跳转，比较：a.intern() == a
         34: iconst_1             // 1(int)值入栈。
         35: goto          39     // 无条件跳转到指定位置。
         38: iconst_0             // 0(int)值入栈。
         39: invokevirtual #10    // 运行时方法绑定调用方法 println()     // Method java/io/PrintStream.println:(Z)V
         42: return      // 返回结果
         LineNumberTable: // LineNumberTable属性存在于Code属性中， 它建立了字节码偏移量到源代码行号之间的联系
         line 11: 0
         line 12: 3
         line 13: 23
         line 14: 42
         LocalVariableTable:  // LocalVariableTable 属性建立了方法中的局部变量与源代码中的局部变量之间的对应关系, 这个属性存在于Code属性中.
         Start  Length  Slot  Name   Signature
         0      43     0  args   [Ljava/lang/String;
         3      40     1     b   Ljava/lang/String;
         23      20     2     a   Ljava/lang/String;
         StackMapTable: number_of_entries = 2
         frame_type = 255 /* full_frame
        offset_delta = 38
        locals = [ class "[Ljava/lang/String;", class java/lang/String, class java/lang/String ]
        stack = [ class java/io/PrintStream ]
        frame_type = 255 /* full_frame
        offset_delta = 0
        locals = [ class "[Ljava/lang/String;", class java/lang/String, class java/lang/String ]
        stack = [ class java/io/PrintStream, int ]
    }
    SourceFile: "ConstantPool.java"


        */
}
